package cn.wangqi.personal.wxpay.util.webconfig;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.UUID;


/**
 * Created by Stream on 2015/11/24.
 */
public class WxPayApi {
    private static Logger logger = LoggerFactory.getLogger(WxPayApi.class);

    public static String GenerateNonceStr() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 提交给统一下单API的参数
     * @param inputObj
     * @return
     * @throws NoSuchAlgorithmException
     * @throws ParserConfigurationException
     * @throws SAXException
     * @throws IOException
     */
    public static Map UnifiedOrder(Map inputObj)
            throws Exception {
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        // 检测必填参数
        if (!inputObj.containsKey("out_trade_no")) {
            throw new RuntimeException("缺少统一支付接口必填参数out_trade_no！");
        } else if (!inputObj.containsKey("body")) {
            throw new RuntimeException("缺少统一支付接口必填参数body！");
        } else if (!inputObj.containsKey("total_fee")) {
            throw new RuntimeException("缺少统一支付接口必填参数total_fee！");
        } else if (!inputObj.containsKey("trade_type")) {
            throw new RuntimeException("缺少统一支付接口必填参数trade_type！");
        }

        // 关联参数
        if (inputObj.get("trade_type").toString()
                .equalsIgnoreCase("JSAPI")
                && !inputObj.containsKey("openid")) {
            throw new RuntimeException(
                    "统一支付接口中，缺少必填参数openid！trade_type为JSAPI时，openid为必填参数！");
        }
        if (inputObj.get("trade_type").toString()
                .equalsIgnoreCase("NATIVE")
                && !inputObj.containsKey("product_id")) {
            throw new RuntimeException(
                    "统一支付接口中，缺少必填参数product_id！trade_type为JSAPI时，product_id为必填参数！");
        }

        // 异步通知url未设置，则使用配置文件中的url
        if (!inputObj.containsKey("notify_url")) {
            inputObj.put("notify_url", WebPayConfig.NOTIFY_URL);// 异步通知url
        }
        String xml = fillRequestData(inputObj);
        String resXml = HttpUtil.postData(url, xml);
        return processResponseXml(resXml);
    }

    /**
     * 向 Map 中添加 appid、mch_id、nonce_str、sign_type、sign <br>
     * 该函数适用于商户适用于统一下单等接口，不适用于红包、代金券接口
     *
     * @param reqData
     * @return
     * @throws Exception
     */
    public static String fillRequestData(Map<String, String> reqData) throws Exception {
        reqData.put("appid", WebPayConfig.APPID);// 公众账号ID
        reqData.put("mch_id", WebPayConfig.MCH_ID);// 商户号
        reqData.put("spbill_create_ip", WebPayConfig.IP);// 终端ip
        reqData.put("nonce_str", GenerateNonceStr());// 随机字符串
        //reqData.put("sign_type", "MD5");
         return WXPayUtil.generateSignedXml(reqData, WebPayConfig.KEY);
    }

    /**
     * 处理 HTTPS API返回数据，转换成Map对象。return_code为SUCCESS时，验证签名。
     * @param xmlStr API返回的XML格式数据
     * @return Map类型数据
     * @throws Exception
     */
    public static Map<String, String> processResponseXml(String xmlStr) throws Exception {
        String RETURN_CODE = "return_code";
        String return_code;
        Map<String, String> respData = WXPayUtil.xmlToMap(xmlStr);
        if (respData.containsKey(RETURN_CODE)) {
            return_code = respData.get(RETURN_CODE);
        }
        else {
            throw new Exception(String.format("No `return_code` in XML: %s", xmlStr));
        }

        if (return_code.equals("FAIL")) {
            return respData;
        }
        else if (return_code.equals("SUCCESS")) {
            if (isResponseSignatureValid(respData)) {
                return respData;
            }
            else {
                throw new Exception(String.format("Invalid sign value in XML: %s", xmlStr));
            }
        }
        else {
            throw new Exception(String.format("return_code value %s is invalid in XML: %s", return_code, xmlStr));
        }
    }

    public static boolean isResponseSignatureValid(Map<String, String> reqData) throws Exception {
        // 返回数据的签名方式和请求中给定的签名方式是一致的
        return WXPayUtil.isSignatureValid(reqData,WebPayConfig.KEY);
    }

}
